/********************************************************************//**
* @file		EventBase.hpp
* @brief	Base of any events
* 
************************************************************************/
#ifndef __EVENTBASE_HPP__
#define __EVENTBASE_HPP__

#include "EventTypes.hpp"
#include <boost/lexical_cast.hpp>

namespace event
{

    /**
     * @class    EventBase
     * @brief    Basic class of any existing event
     */
    class EventBase
    {
    protected:
        void * m_sender;    /// sender of the event
        float m_TimeToWait; /// time to wait before firing the event
        float m_CurrentTime; /// current time to wait before firing the event
        int m_RemainingFires; /// number of time we have to fire this event

    protected:
        enum_typeEvent m_TypeEvent; /// type of the event

        /**
         * @fn       EventBase(enum_typeEvent    _typeEvent = MAX_EVENT_TYPE, float _timeToWait = 0, int _nbFires = 0)
         * @brief    Contructor
         * @param    _typeEvent      type of event
         * @param    _timeToWait     time we have to wait before firing the event
         * @param    _nbFires        number of time we have to fire the event
         */
        EventBase(enum_typeEvent _typeEvent = MAX_EVENT_TYPE, float _timeToWait = 0, int _nbFires = 0)
        : m_TypeEvent(_typeEvent),
        m_TimeToWait(_timeToWait),
        m_CurrentTime(_timeToWait),
        m_RemainingFires(_nbFires)
        {
        }

    public:

		struct _RemoveByTime_
		{
			bool operator()( boost::shared_ptr<EventBase> _event )
			{
				return ( _event->getRemainingFires() <= 0 && _event->getRemainingTime() <= 0);
			}
		};
        /**
         * @fn       EventBase(void* _sender, enum_typeEvent    _typeEvent = MAX_EVENT_TYPE, float _timeToWait = 0, int _nbFires = 0)
         * @brief    Contructor
         * @param    _typeEvent      type of event
         * @param    _timeToWait     time we have to wait before firing the event
         * @param    _nbFires        number of time we have to fire the event
         */
        EventBase(void* _sender, enum_typeEvent _typeEvent = MAX_EVENT_TYPE, float _timeToWait = 0, int _nbFires = 0)
        : m_sender(_sender),
        m_TypeEvent(_typeEvent),
        m_TimeToWait(_timeToWait),
        m_CurrentTime(_timeToWait),
        m_RemainingFires(_nbFires)
        {
        }

        /**
         * @fn       EventBase(const EventBase& orig)
         * @brief    Copy Contructor
         * @param    orig       Copy of the event we have to do
         */
        EventBase(const EventBase& orig)
        : m_sender(orig.m_sender),
        m_TypeEvent(orig.m_TypeEvent),
        m_TimeToWait(orig.m_TimeToWait),
        m_CurrentTime(orig.m_CurrentTime),
        m_RemainingFires(orig.m_RemainingFires)
        {
        }

        /**
         * @fn       ~EventBase()
         * @brief    Virtual Destructor
         */
        virtual ~EventBase()
        {
        }
		
		virtual void setAttribute( std::string _name, std::string _value )
		{
			if( _name == "TimeToWait" )
				m_TimeToWait = boost::lexical_cast< float >( _value );
			if( _name == "NbFires" )
				m_RemainingFires = boost::lexical_cast< int >( _value );
		}

		virtual void getAttribute( std::string& _name, std::string& _value )
		{
		}

        /**
         * @fn       getSender() 
         * @brief    getter on the sender of the event
         * @return   the sender of the event
         */
        inline void* getSender() 
        {
            return m_sender;
        }

        /**
         * @fn       getType() const
         * @brief    getter on the type of the event
         * @return   the type of the event
         */
        inline enum_typeEvent getType() const
        {
            return m_TypeEvent;
        }

        /**
         * @fn       getRemainingTime() const
         * @brief    getter on the remaining time we have to wait before firing the event
         * @return   the remaining time we have to wait before firing the event
         */
        inline float getRemainingTime() const
        {
            return m_CurrentTime;
        }

        /**
         * @fn       getRemainingFires() const
         * @brief    getter on the remaining times we have to fire the event
         * @return   the remaining times we have to fire the event
         */
        inline int getRemainingFires() const
        {
            return m_RemainingFires;
        }

        /**
         * @fn       resetTime()
         * @brief    reset the current time to the init time to wait
         */
        inline void resetTime()
        {
            m_CurrentTime = m_TimeToWait;
        }

        /**
         * @fn       fire()
         * @brief    the event is fired, we decrement the remaining fires and reset the time
         * @return   the number of remaining firing we have to do
         */
        inline int fired()
        {
			if( m_RemainingFires > 0 )
				resetTime();
            return (--m_RemainingFires);
        }

		void setTimeToWait( float _timeToWait )
		{
			m_TimeToWait = _timeToWait;
		}

        /**
         * @fn       update(float _time)
         * @brief    decrement the current time
         * @param    _time       the time elapsed since the last frame
         * @return   the remaining time we have to wait time
         */
        inline float update(float _time)
        {
            return (m_CurrentTime -= _time);
        }

        bool operator<(EventBase& _evtRight)
        {
            return (m_CurrentTime < _evtRight.m_CurrentTime);
        }
    };

} //  namespace event



#endif //__EVENTBASE_HPP__
